package com.yudean.esb.controller;

import cn.hutool.core.date.DateUtil;
import com.google.common.base.Joiner;
import com.yudean.esb.common.Constants;
import com.yudean.esb.common.ServiceConstant;
import com.yudean.esb.domain.erp.IdsPmProAppr;
import com.yudean.esb.domain.erp.IdsPmProTech;
import com.yudean.esb.exception.InvalidateXmlContentException;
import com.yudean.esb.mapper.mds.IdsPmProTechMapper;
import com.yudean.esb.security.SecurtiyChecker;
import com.yudean.esb.security.impl.SecurtiyChekerImpl;
import com.yudean.esb.service.IdsPmProApprService;
import com.yudean.esb.service.IdsPmProTechService;
import com.yudean.esb.util.ParseResult;
import com.yudean.esb.util.StringUtil;
import com.yudean.esb.util.XmlResult;
import com.yudean.esb.util.XmlUtil;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 生产项目管理系统接口
 * 年度申报项目和批复数据
 */
@RestController
@Slf4j
@RequestMapping("/ids-pm-pro-tech")
public class IdsPmProTechController {

    private IdsPmProTechService idsPmProTechService;
    private IdsPmProTechMapper idsPmProTechMapper;
    private SecurtiyChecker securtiyChecker;
    @Resource
    private IdsPmProApprService idsPmProApprService;

    @Autowired
    public void setIdsPmProTechMapper(IdsPmProTechMapper idsPmProTechMapper) {
        this.idsPmProTechMapper = idsPmProTechMapper;
    }
    @Autowired
    public void setIdsPmProTechService(IdsPmProTechService idsPmProTechService) {
        this.idsPmProTechService = idsPmProTechService;
    }
    @Autowired
    public void setSecurtiyChecker(SecurtiyChecker securtiyChecker) {
        this.securtiyChecker = securtiyChecker;
    }

    /**
     * 根据ID获取生产项目记录
     *
     * @param id 项目ID:TechID
     * @return XML格式返回生产项目记录
     */
    @ApiOperation(value = "根据单个项目ID获取生产项目记录",notes = "根据单个项目ID获取生产项目记录的接口")
    @ApiImplicitParam(name = "id",value = "项目ID",paramType = "query",required = true,dataType = "String")
    @GetMapping("/id")
    public String findById(@RequestParam String token, @RequestParam String id){
        log.info("通过项目ID获取生产项目记录findById(),date={}，ID={}", DateUtil.now(),id);
        //权限校验
        if(!securtiyChecker.validate(ServiceConstant.SERVICE_ID,token)){
            SecurtiyChekerImpl securtiyCheckerImpl = (SecurtiyChekerImpl) securtiyChecker;
            return XmlUtil.bean2Xml(new XmlResult(ServiceConstant.SERVICE_ID,token,securtiyCheckerImpl.getErrorCode(),securtiyCheckerImpl.getErrorMsg()));
        }
        return idsPmProTechService.findById(id);
    }

    /**
     * 将传递进来的参数封装成Map
     * @param thchProjectCode 项目编码
     * @return String
     */
    @ApiOperation(value = "根据项目编号获取生产项目记录",notes = "根据项目编号获取生产项目记录的接口")
    @ApiImplicitParam(name = "thchProjectCode",value = "项目编号",paramType = "query",required = true,dataType = "String")
    @GetMapping("/projectCode")
    public String findByProjectCode(@RequestParam String token,@RequestParam String thchProjectCode){
        log.info("通过项目编码查询生产项目记录findXmlByProjectCode(),date={},techProjectCode={}",DateUtil.now(),thchProjectCode);
        //权限校验
        if(!securtiyChecker.validate(ServiceConstant.SERVICE_ID,token)){
            SecurtiyChekerImpl securtiyCheckerImpl = (SecurtiyChekerImpl) securtiyChecker;
            return XmlUtil.bean2Xml(new XmlResult(ServiceConstant.SERVICE_ID,token,securtiyCheckerImpl.getErrorCode(),securtiyCheckerImpl.getErrorMsg()));
        }
        HashMap<String,Object> map = new HashMap<>();
        map.put("TECHPROJECTCODE",thchProjectCode);
        return idsPmProTechService.findByMultiCondition(map);
    }

    /**
     * 根据id批量查询
     * @param ids 多个项目ID
     * @return XML
     */
    @PostMapping("/ids")
    @ApiOperation(value = "根据多个项目ID获取生产项目记录",notes = "根据项目编号获取生产项目记录的接口")
    public String findByIds(@RequestParam String token,@RequestBody List<String> ids){
        log.info("根据多个项目ID获取生产项目记录findByIds(),time={},list={}",DateUtil.now(),ids);
        //权限校验
        if(!securtiyChecker.validate(ServiceConstant.SERVICE_ID,token)){
            SecurtiyChekerImpl securtiyCheckerImpl = (SecurtiyChekerImpl) securtiyChecker;
            return XmlUtil.bean2Xml(new XmlResult(ServiceConstant.SERVICE_ID,token,securtiyCheckerImpl.getErrorCode(),securtiyCheckerImpl.getErrorMsg()));
        }
        return idsPmProTechService.findByIds(ids);
    }

    /**
     * 分页查询
     * @param token 定义的服务的唯一标示
     * @param pageNo 页码
     * @param pageSize 每页显示条数
     * @return XML String
     */
    @GetMapping("/")
    @ApiOperation(value = "分页查询生产项目记录",notes = "分页查询生产项目记录的接口")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "pageNo",value = "页码",paramType = "query",required = true,dataType = "String"),
            @ApiImplicitParam(name = "pageSize",value = "每页显示条数",paramType = "query",required = true,dataType = "String")
    })
    public String findByPage(@RequestParam String token,@RequestParam String pageNo, @RequestParam String pageSize){
        log.info("分页查询findByPage(),time={}pageNo={},pageSize={}",DateUtil.now(),pageNo,pageSize);
        //权限校验
        if(!securtiyChecker.validate(ServiceConstant.SERVICE_ID,token)){
            SecurtiyChekerImpl securtiyCheckerImpl = (SecurtiyChekerImpl) securtiyChecker;
            return XmlUtil.bean2Xml(new XmlResult(ServiceConstant.SERVICE_ID,token,securtiyCheckerImpl.getErrorCode(),securtiyCheckerImpl.getErrorMsg()));
        }
        return idsPmProTechService.findByPage(pageNo,pageSize);
    }

    /**
     * 推送数据的接口
     * @param serviceID 定义的服务的唯一标识
     * @param token 安全令牌
     * @param data xml格式的数据集
     * @return Result XML String
     */
    @PostMapping("/upload")
    @ApiOperation(value = "推送生产项目记录",notes = "推送生产项目记录的接口")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "serviceID",value = "定义的服务的唯一标识",required = true,dataType = "String"),
            @ApiImplicitParam(name = "token",value = "安全令牌",required = true,dataType = "String")
    })
    public String put(@RequestParam String serviceID,@RequestParam String token,@RequestParam String data){
        log.info("put():request-{time:{},serviceID:{},token:{},data:{}}",DateUtil.now(),serviceID,token,data);
        //权限校验
        if(!securtiyChecker.validate(serviceID,token)){
            SecurtiyChekerImpl securtiyCheckerImpl = (SecurtiyChekerImpl) securtiyChecker;
            return XmlUtil.bean2Xml(new XmlResult(serviceID,token,securtiyCheckerImpl.getErrorCode(),securtiyCheckerImpl.getErrorMsg()));
        }
        //XML数据集非空校验
        if(data == null || "".equals(data.trim())||"\"\"".equals(data.trim())){
            log.error("data数据集为空");
            return ServiceConstant.noData(serviceID,token);
        }
        //替换+号，避免出现+号被替换为空的情况
        if(data.indexOf("+") > 0){
            data = data.replaceAll("\\+", "%2B");
        }

        //XML数据集编码校验
        try {
            data = URLDecoder.decode(data,"UTF-8");
        }catch (IllegalArgumentException | UnsupportedEncodingException exception){
            log.error("data URLDecode error");
            exception.printStackTrace();
            return XmlUtil.bean2Xml(new XmlResult(serviceID,token, Constants.SC_MESSAGE_ERROR,Constants.SC_MESSAGE_ERROR_ENCODE_MSG));
        }
        //替换出现的反斜杠"\"为正斜杠"/"
        if (data.indexOf("\\") > 0) {
            data = data.replaceAll("\\\\", "/");
        }

        //批量数据导入
        ParseResult parseResult = null;
        //更新成功记录数
        int updateCount = 0;
        //新增成功记录数
        int insertCount = 0;
        //插入或更新失败的记录ID
        List<String> errorList = new ArrayList<>();
        //解析成功的记录数
        int parseCount = 0;
        //插入或更新影响的记录数
        int res;
        String errorMsg = ",违反唯一性约束:";
        try {
            if(ServiceConstant.SERVICE_ID.equals(serviceID)){
                parseResult = XmlUtil.parseListFromXml(data, IdsPmProTech.class);
                List<IdsPmProTech> idsPmProTeches = parseResult.getData();
                parseCount = idsPmProTeches.size();
                for (IdsPmProTech idsPmProTech : idsPmProTeches) {
                    if(StringUtil.isEmpty(idsPmProTech.getTechprojectcode()) || StringUtil.isEmpty(idsPmProTech.getTechcompanyid())||idsPmProTech.getTechyeah()==null||StringUtil.isEmpty(idsPmProTech.getTechname())){
                        log.error("项目数据有误，项目编码、公司三字码、年份和项目名称存在NULL值,techProjectCode={},techCompanyId={},techYeah={},techName={}",
                                idsPmProTech.getTechprojectcode(), idsPmProTech.getTechcompanyid(),idsPmProTech.getTechyeah(),idsPmProTech.getTechname());
                        errorList.add(idsPmProTech.getTechid());
                        continue;
                    }
                    IdsPmProTech pmProTech = idsPmProTechMapper.selectById(idsPmProTech.getTechid());
                    Map<String,Object> map = new HashMap<>();
                    res = 0;
                    try{
                        if(pmProTech != null){
                            //update record
                            res = idsPmProTechMapper.updateById(idsPmProTech);
                            updateCount += res;
                        }else{
                            //insert record
                            res = idsPmProTechMapper.insert(idsPmProTech);
                            insertCount += res;
                        }
                    }catch (RuntimeException exception){
                        String message = exception.getCause().getLocalizedMessage();
                        if(message.contains("ORA-00001:")){
                            log.error("违反唯一性约束,ID:{}",idsPmProTech.getTechid());
                            errorMsg += idsPmProTech.getTechid()+" ";
                        }
                    }
                    //插入或者更新不成功，在错误列表中新增techid
                    if(res == 0){
                        errorList.add(idsPmProTech.getTechid());
                    }
                }
            }else if(ServiceConstant.SERVICE_ID_APPR.equals(serviceID)){
                parseResult = XmlUtil.parseListFromXml(data, IdsPmProAppr.class);
                List<IdsPmProAppr> idsPmProAppres = parseResult.getData();
                parseCount = idsPmProAppres.size();
                for (IdsPmProAppr idsPmProAppr : idsPmProAppres) {
                    if(StringUtil.isEmpty(idsPmProAppr.getTechprojectcode()) || idsPmProAppr.getTechyeah() == null){
                        log.error("批复审批数据有误，年份和项目编码不能为空techName={},techYeah={},techProjectCode={}",idsPmProAppr.getTechname(),idsPmProAppr.getTechyeah(),idsPmProAppr.getTechprojectcode());
                        errorList.add(idsPmProAppr.getTechname()+"(techName)");
                        continue;
                    }
                    Map<String,Object> map = new HashMap<>();
                    map.put("TECHPROJECTCODE",idsPmProAppr.getTechprojectcode());
                    map.put("TECHYEAH",idsPmProAppr.getTechyeah());
                    final IdsPmProAppr PmProAppr = idsPmProApprService.selectByMap(map);
                    res = 0;
                    try{
                        if(PmProAppr != null){
                            //update record
                            res = idsPmProApprService.updateByMap(idsPmProAppr,map);
                            updateCount += res;
                        }else{
                            //insert record
                            res = idsPmProApprService.insertObj(idsPmProAppr);
                            insertCount += res;
                        }
                    }catch (RuntimeException exception){
                        String message = exception.getCause().getLocalizedMessage();
                        if(message.contains("ORA-00001:")){
                            log.error("违反唯一性约束,ID:{}",idsPmProAppr.getTechprojectcode());
                            errorMsg += idsPmProAppr.getTechprojectcode()+" ";
                        }
                    }

                    if(res == 0){
                        errorList.add(idsPmProAppr.getTechprojectcode()+idsPmProAppr.getTechyeah());
                    }
                }
            }
        }catch (InvalidateXmlContentException exception){   //xml解析异常
            log.error("xml解析异常，exception-{}",exception.getMessage());
            return XmlUtil.bean2Xml(new XmlResult(serviceID,token,Constants.SC_MESSAGE_ERROR,Constants.SC_MESSAGE_ERROR_MSG));
        }
        log.info("推送数据总记录数:{},解析成功记录数:{},插入成功记录数:{},更新成功记录数:{}",parseResult.getReceived(),parseResult.getSubmitted(),insertCount,updateCount);
        if(errorList.size()>0||parseResult.getReceived()> parseResult.getSubmitted()){
            log.error("插入或更新失败的记录:{}，解析失败的记录:{}", Joiner.on(",").join(errorList),Joiner.on(",").join(parseResult.getErrIds()));
        }
        //合并解析失败和插入、更新失败的记录
        List<String> errList = new ArrayList<>();
        errList.addAll(parseResult.getErrIds());
        errList.addAll(errorList);

        //插入或更新无错误
        if (errorList.size() == 0){
            //部分数据解析出错，解析成功的数据全部插入或更新成功
            if(parseResult.getReceived() > parseResult.getSubmitted()){
                log.error("put():Part of the data pushed successfully,Error data ID:{}", Joiner.on(",").join(parseResult.getErrIds()));
                return ServiceConstant.okMsg(serviceID,token,parseResult.getReceived(),parseResult.getSubmitted(),
                        Constants.CODE_SUCCESS,"部分数据解析并插入成功,解析错误的记录为".concat(Joiner.on(",").join(parseResult.getErrIds())));
            }else{
                //全部数据解析并插入/更新成功
                log.info("put():process data success");
                return ServiceConstant.okMsg(serviceID,token,parseResult.getReceived(),parseResult.getSubmitted(),Constants.CODE_SUCCESS,
                        Constants.CODE_SUCCESS_MSG);
            }
            //插入或更新存在错误
        }else {
            //解析成功的数据全部插入/更新失败
            if(errorList.size() == parseCount){
                log.error("put():process data fail.parse error data id:{},update or insert error record id:{}",
                        Joiner.on(",").join(parseResult.getErrIds()),Joiner.on(",").join(errorList));
                return ServiceConstant.okMsg(serviceID,token,parseResult.getReceived(),0,
                        Constants.CODE_OTHER_ERROR,"数据有误");
                //解析成功的数据，部分插入成功
            } else{
                log.info("Part of the data update or insert failed,parse error data id:{},update or insert error record id:{}",
                        Joiner.on(",").join(parseResult.getErrIds()),Joiner.on(",").join(errorList));
                return ServiceConstant.okMsg(serviceID,token,parseResult.getReceived(),parseResult.getSubmitted()-errorList.size(),
                        Constants.CODE_SUCCESS, "部分数据解析并插入成功,解析或插入错误的记录为".concat(Joiner.on(",").join(errList))+errorMsg);
            }
        }
    }


}
